<?php
/**
 *
 * @todo description of this class
 *
 * @author Alton Crossley <crossleyframework@nogahidebootstrap.com>
 * @package Crossley Framework
 *
 * @copyright Copyright (c) 2003-2009, Nogaide BootStrap INC. All rights reserved.
 * @license BSD http://opensource.org/licenses/bsd-license.php
 * @version $Id:$
 *
 */

/**
 * @namespace
 */
namespace X\Controller\Response;

/**
 * purpose: to construct the Standard Object Response for the Controller
 *
 * @author Alton Crossley
 * @package Crossley Framework
 * @version 0.3
 *
 */
class Standard implements \X\Controller\Response
{
    /**
     * signifies a JSON array is returned
     *
     */
    const ENCODE_JSON = 'json';
    /**
     * signifies a HTML string is returned
     *
     */
    const ENCODE_HTML = 'html';
    /**
     * signifies a complex type is returned
     *
     */
    const ENCODE_COMPLEX = 'complex';
    
    /**
     * HTML markup/output, if any
     *
     * @var string
     */
    protected $_Html = '';
    
    /**
     * Does this Response have any errors?
     * @var boolean
     */
    public $hasError = false;
    
    /**
     * What are the global error messages?
     * These are *not* validation errors,
     * but more general errors.
     * @var array
     */
    public $ErrorMessages = array();
    
    /**
     * The result 'data'
     *
     * @var array
     */
    public $Data = array();
    
    /**
     * JS and CSS external file dependencies
     *
     * @example array($this->_JS_Key => array('js/foo.js', js/foo2.js), $this->_CSS_Key => array('style/foo.css'));
     *
     * @var array 2D array
     */
    public $Dependencies = array();
    
    /**
     * Bus messages (this is Alton's thing)
     * @var array
     */
    public $BusMessages = array();
    
    /**
     * method of output
     * @var string
     */
    protected $_OutputMethod = 'default';
    
    /**
     * key used in dependency array for javascript URIs
     * @var string
     */
    protected $_JS_Key = 'js';
    /**
     * key used in dependency array for css URIs
     * @var string
     */
    protected $_CSS_Key = 'css';
    /**
     * key used for form data in the json encoded response
     * @var string
     */
    protected $_Form_Key = 'Form';
    /**
     * key used in response array indicating validation errors
     * @var string
     */
    protected $_ValidationError_Key = 'ValidationErrors';
    /**
     * key used in response array indicating html content
     * @var string
     */
    protected $_RenderName = 'Html';
    /**
     * constructor allowing the setting of HTML/String content
     * @param string $content
     */
    function __construct($content = null)
    {
        if ($content) $this->Html($content);
    }
    /**
     * Get and/or Set the response output method using class constants
     *
     * @param string $Mode
     */
    public function OutputMethod($Mode = null)
    {
        switch ($Mode) {
            case null:
                return $this->_OutputMethod;
                break;
            case self::ENCODE_COMPLEX:
                $this->_OutputMethod = self::ENCODE_COMPLEX;
                break;
            case self::ENCODE_JSON:
                $this->_OutputMethod = self::ENCODE_JSON;
                break;
            default:
                $this->_OutputMethod = self::ENCODEHTML;
                break;
        }
        
        return $this->_OutputMethod;
    }
    
    /**
     * Add a global error message
     *
     * @param string $sError
     */
    public function addError($Error)
    {
        $this->ErrorMessages[] = $Error;
        $this->hasError = true;
    }
    
    /**
     * Set all errors as an array
     *
     * @param array $aErrors
     */
    public function setErrors(array $Errors)
    {
        $this->ErrorMessages = $Errors;
        if (! empty($Errors))
        {
            $this->hasError = true;
        }
    }
    
    /**
     * check to see if there are errors in the response
     *
     * @return bool
     */
    public function hasErrors()
    {
        return (bool) $this->hasError;
    }
    
    /**
     * Remove errors
     *
     */
    public function removeErrors()
    {
        $this->ErrorMessages = array();
        $this->hasError = false;
    }
    
    /**
     * retrieve error messages array
     *
     * @return array
     */
    public function getErrors()
    {
        return $this->ErrorMessages;
    }
    
    /**
     * Add any kind of data *by key*
     * (aForm and aValidationErrors are reserved)
     *
     * @param string $sKey
     * @param mixed $mValue
     */
    public function addData($Key, $Value)
    {
        // form data and validation errors set on their own methods
        if ($Key != $this->_Form_Key &&
         $Key != $this->_ValidationError_Key)
        {
            $this->Data[$Key] = $Value;
        }
    }
    
    /**
     * Add form data (field/value)
     *
     * @param array $aFormData
     */
    public function addFormData(array $FormData, $Merge = false)
    {
        if (array_key_exists($this->_Form_Key, $this->Data) && $Merge)
        {
            $this->Data[$this->_Form_Key] = array_merge($this->Data[$this->_Form_Key], $FormData);
        }
        else
        {
            $this->Data[$this->_Form_Key] = $FormData;
        }
    }
    
    public function getFormData()
    {
        return (array_key_exists($this->_Form_Key, $this->Data) ? $this->Data[$this->_Form_Key] : array());
    }
    
    /**
     * Get/Set Html Content
     * Enter description here ...
     * @param string $Html
     */
    public function Html($Html = null)
    {
        if ($Html != null) $this->_Html = $Html;        
        return $this->_Html;
    }
    
    /**
     * Add validation errors
     * (error messages keyed by dom id)
     *
     * @param array $aValidationErrors
     */
    public function addValidationErrors(array $ValidationErrors)
    {
        $this->Data[$this->_ValidationError_Key] = $ValidationErrors;
    }
    
    /**
     * Does this reponse have validation errors?
     *
     * @return boolean
     */
    public function hasValidationErrors()
    {
        return (array_key_exists($this->_ValidationError_Key, $this->Data) &&
         ! empty($this->Data[$this->_ValidationError_Key]));
    }
    
    /**
     * Get the standard array
     * This is the main benefit here -- easy encapsulation
     * of a complex array:
     *
     * hasError - simply a boolean indicating if errors were encountered
     * in processing
     * ErrorMessages - array of strings that are the actual errors encountered
     * Result - the actual result of the request
     * [HTML] - the html string built in the request.  Not always populated
     * [Data] - JSON object result of the request. Not always populated
     * BusMessages - array of JSON bus message objects which are published
     * onto the event bus
     * Dependencies - array of string urls of dependencies
     * [js] = array of javascript urls
     * [css] = array of css urls
     *
     * @return array
     */
    public function getArray()
    {
        return array('hasError' => $this->hasError, 
        'ErrorMessages' => $this->ErrorMessages, 
        'Result' => array('Data' => $this->Data, 'HTML' => $this->Html), 
        'BusMessages' => $this->BusMessages, 
        'Dependencies' => $this->Dependencies);
    }
    
    /**
     * direct access to the result data
     * this overwrites any data currently in place
     *
     * @param unknown_type $xData
     */
    public function setData($Data)
    {
        $this->Data = $Data;
    }
    
    /**
     * add a js url to the dependency list
     *
     * @param stirng $sURL
     */
    public function addJavaScriptDependency($URL)
    {
        if (is_string($URL))
        {
            if (array_search($URL, $this->Dependencies[$this->_JS_Key]) === false)
            {
                array_push($this->Dependencies[$this->_JS_Key], trim($URL));
            }
        }
        elseif (is_array($URL))
        {
            foreach ($URL as $Url)
            {
                $this->addJavaScriptDependency((string) $Url);
            }
        }
        else
        {
            $this->addJavaScriptDependency((string) $URL);
        }
    
    }
    
    /**
     * add a css url to the dependency list
     *
     * @param string $sURL
     */
    public function addCSSDependency($URL)
    {
        array_push($this->Dependencies[$this->_CSS_Key], $URL);
    }
    
    /**
     * overwrite the dependency array
     *
     * @param array $aDependencies
     */
    public function setDependencies(Array $Dependencies)
    {
        if (! array_key_exists($this->_JS_Key, $Dependencies) ||
         ! array_key_exists($this->_CSS_Key, $Dependencies))
        {
            trigger_error(
                'dependency array set to incomplete array structure ("' .
                 $this->_JS_Key . '" or "' . $this->_CSS_Key . '" keys missing)', 
                E_USER_NOTICE);
        }
        
        $this->Dependencies = $Dependencies;
    }
    
    /**
     * gather dependencies in their respective rendered strings
     *
     * @return string
     */
    public function getDependencyString()
    {
        $Return = '';
        foreach ($this->Dependencies[$this->_JS_Key] as $JsUrl)
        {
            $Script = new \X\HTML\Script($JsUrl);
            $Return .= (string) $Script;
        }
        
        foreach ($this->Dependencies[$this->_CSS_Key] as $CssUrl)
        {
            $Link = new \X\HTML\Link\Stylesheet($CssUrl);
            $Return .= (string) $Link;
        }
        
        return $Return;
    }
    
    /**
     * Set the name used in rendering this response
     *
     * @param string $Name
     */
    public function setRenderName($Name)
    {
        $this->_RenderName = $Name;
    }
    
    /**
     * retrieve the name used to render the response
     *
     */
    public function getRenderName()
    {
        return $this->_RenderName;
    }
    
    /**
     * standard toString returns JSON array
     *
     * @return srting
     */
    function __toString()
    {
        switch ($this->_OutputMethod) {
            case self::ENCODE_COMPLEX:
                // @TODO make it possible to pass out your own structure
                return json_encode($this->getArray());
                break;
            case self::ENCODE_JSON:
                return json_encode($this->getArray());
                break;
            default:
                return $this->_Html;
                break;
        }
    
    }
}